/**
 * Check if an element has a class
 * @param {HTMLElement} ele
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele: HTMLElement, cls: string) {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}

/**
 * Add class to element
 * @param {HTMLElement} ele
 * @param {string} cls
 */
export function addClass(ele: HTMLElement, cls: string) {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls;
}

/**
 * Remove class from element
 * @param {HTMLElement} ele
 * @param {string} cls
 */
export function removeClass(ele: HTMLElement, cls: string) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
    ele.className = ele.className.replace(reg, ' ');
  }
}

/**
 * 判断是否是外部链接
 *
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path: string) {
  const isExternal = /^(https?:|http?:|mailto:|tel:)/.test(path);
  return isExternal;
}

/**
 * 格式化增长率，保留两位小数 ，并且去掉末尾的0  取绝对值
 *
 * @param growthRate
 * @returns
 */
export function formatGrowthRate(growthRate: number) {
  if (growthRate === 0) {
    return '-';
  }

  const formattedRate = Math.abs(growthRate * 100)
    .toFixed(2)
    .replace(/\.?0+$/, '');
  return formattedRate + '%';
}

export function validateNum(num: any) {
  return (
    num !== null &&
    num !== undefined &&
    num !== '' &&
    num !== false &&
    num !== 'null' &&
    num !== 'undefined' &&
    !Number.isNaN(num)
  );
}

export const comparePercentage = (str: string = '') => {
  try {
    // 1. 清理输入：去除首尾空格 + 移除百分号 + 移除千分位逗号
    const cleaned = str.trim().replace(/%$/, '').replace(/,/g, '');

    // 2. 转换为浮点数
    const num = parseFloat(cleaned);

    // 3. 验证是否为有效数字
    if (isNaN(num) || !cleaned.match(/^[-+]?\d*\.?\d+$/)) {
      return '无效的百分比格式';
    }

    return num;
  } catch (error) {
    console.log('Invalid-', error);
  }
};

// 定义一个函数，将嵌套对象转换为GET请求参数的格式
export function objectToQueryString(obj: object, parentKey: string = '') {
  const parts = [];
  for (let key in obj) {
    if (!obj.hasOwnProperty(key)) continue; // 确保key是对象自身的属性，而不是继承来的
    let value = obj[key];
    let newKey = parentKey ? `${parentKey}[${key}]` : key; // 如果有父级key，则使用带有方括号的形式
    if (typeof value === 'object') {
      parts.push(objectToQueryString(value, newKey)); // 递归处理嵌套对象
    } else {
      parts.push(encodeURIComponent(newKey) + '=' + encodeURIComponent(value)); // 处理普通的键值对
    }
  }
  return parts.join('&'); // 将处理后的键值对用&连接起来
}

// 防抖 n 秒内再次触发 则重新计时 直至 n 秒内的最后一次触发
export const debounce = (fn: Function, delay = 300) => {
  let timer: any = null;
  return (...args: any[]) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      // fn.apply(this, args);
      fn(...args);
      timer = null;
    }, delay);
  };
};

/**
 * 节流函数 不管怎么点击，只在 delay 毫秒内触发事件，300 毫秒内点击也要等到300 毫秒后再触发事件
 * @param {Function} fn 要节流的函数
 * @param {number} delay 节流的时间间隔，单位毫秒
 * @returns {Function} 节流后的函数
 */
export const throttle = (fn: Function, delay = 300) => {
  let canRun: boolean = true;
  return (...args: any[]) => {
    if (!canRun) return;
    canRun = false;
    setTimeout(() => {
      fn(...args);
      canRun = true;
    }, delay);
  };
};

// 防抖函数高阶(immediate: true 第一次调用直接执行,然后等待delay后，才能delay直接执行)
// 在防抖函数中第三个参数immediate，可以实现这种效果
export function debounceAd(func: Function, delay = 300, immediate = false) {
  let timer: any = null;
  return function () {
    if (timer) clearTimeout(timer);
    // 复杂的防抖函数
    // 判断定时器是否为空，如果不为空，则会直接执行回调函数
    if (immediate) {
      let firstRun = !timer;
      // 不管定时器是否为空，都会重新开启一个新的定时器,不断输入，不断开启新的定时器，当不在输入的delay后，再次输入就会立即执行回调函数
      timer = setTimeout(() => {
        timer = null;
      }, delay);
      if (firstRun) {
        func.apply(this, arguments);
      }
    } else {
      // 简单的防抖函数
      // 不管定时器是否为空，都会重新开启一个新的定时器,不断输入，不断开启新的定时器，当不在输入的delay后，再次输入就会立即执行回调函数
      timer = setTimeout(() => {
        func.apply(this, arguments);
      }, delay);
    }
  };
}
